﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using TheGameClient.Processes;
using TheGameClient.Webservices;
using Waaahsabi.Controls.TheGame;

namespace TheGameClient
{
	public partial class FeatureMailControl : ISystemFeature
	{
		private readonly ObservableCollection<MailControlAccountInfo> _availableAccounts;
		private readonly ObservableCollection<MailControlMailHeader> _currentlyViewingHeaders;
		private List<ShortEmailAccountInfo> _availableAccountInfo = new List<ShortEmailAccountInfo>();
		private ShortEmailAccountInfo _currentAccount;
		private EmailHeader _currentlyViewing;
		private List<EmailHeader> _currentlyViewingEmailHeaders = new List<EmailHeader>();
		private MailFolderType _folder;

		public FeatureMailControl()
		{
			InitializeComponent();
			mailControl.CreateAccount += MailControlCreateAccount;
			mailControl.MailAccountSelected += MailControlMailAccountSelected;
			mailControl.MailFolderSelected += MailControlMailFolderSelected;
			mailControl.MailSelected += MailControlMailSelected;
			mailControl.SendMail += MailCreationControlSendMail;
			mailControl.DeleteMail += MailControlDeleteMail;
			mailControl.MarkMailAsSpam += MailControlMarkMailAsSpam;

			_availableAccounts = new ObservableCollection<MailControlAccountInfo>();
			mailControl.MailAccounts = _availableAccounts;

			_currentlyViewingHeaders = new ObservableCollection<MailControlMailHeader>();
			mailControl.MailHeaders = _currentlyViewingHeaders;
		}

		#region ISystemFeature Members

		public ulong InterfaceId
		{
			get { return new Guid("{8675C4C5-0EB1-445c-AA42-57F10B8F9D8C}").ToLong(); }
		}

		public Guid ProcessId { get; private set; }

		public string ProcessName
		{
			get { return "Mail"; }
		}

		public InterfaceCategory Category
		{
			get { return InterfaceCategory.SystemFeature; }
		}

		public ulong SystemId { get; private set; }

		public void Load(ulong systemId)
		{
			SystemId = systemId;
			App.Client.GetEmailAccountsForSystemCompleted += ClientGetEmailAccountsForSystemCompleted;
			App.Client.GetEmailAccountsForSystemAsync(App.InternalSessionId, SystemId);
			App.Client.GetHostnameAddressCompleted += ClientGetHostnameAddressCompleted;
			App.Client.GetHostnameAddressAsync(App.InternalSessionId, SystemId);
		}

		#endregion

		private void MailControlMarkMailAsSpam(object sender, ModifyMailEventArgs e)
		{
			App.Client.MarkEmailAsSpamCompleted += ClientMarkEmailAsSpamCompleted;
			App.Client.MarkEmailAsSpamAsync(App.InternalSessionId, SystemId, _currentAccount.Id, e.HeaderId);
		}

		private void ClientMarkEmailAsSpamCompleted(object sender, MarkEmailAsSpamCompletedEventArgs e)
		{
			App.Client.MarkEmailAsSpamCompleted -= ClientMarkEmailAsSpamCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (!e.Result)
			{
				MessageBox.Show("Failed to mark mail as spam.");
			}
			mailControl.SelectFolderItem(_folder);
			Load(SystemId);
		}

		private void MailControlDeleteMail(object sender, ModifyMailEventArgs e)
		{
			App.Client.DeleteEmailCompleted += ClientDeleteEmailCompleted;
			App.Client.DeleteEmailAsync(App.InternalSessionId, SystemId, _currentAccount.Id, e.HeaderId);
		}

		private void ClientDeleteEmailCompleted(object sender, DeleteEmailCompletedEventArgs e)
		{
			App.Client.DeleteEmailCompleted -= ClientDeleteEmailCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (!e.Result)
			{
				MessageBox.Show("Failed to delete this mail.");
			}
			mailControl.SelectFolderItem(_folder);
			Load(SystemId);
		}

		private void MailCreationControlSendMail(object sender, EventArgs e)
		{
			App.Client.SendEmailCompleted += ClientSendEmailCompleted;
			var bcc =
				mailControl.MailCreationControl.txtBCC.Text.Replace(" ", "").Split(new[] {";"},
				                                                                   StringSplitOptions.RemoveEmptyEntries).ToList();
			if (bcc.Count == 0 && !string.IsNullOrEmpty(mailControl.MailCreationControl.txtBCC.Text))
				bcc.Add(mailControl.MailCreationControl.txtBCC.Text);

			var cc =
				mailControl.MailCreationControl.txtCC.Text.Replace(" ", "").Split(new[] {";"}, StringSplitOptions.RemoveEmptyEntries)
					.ToList();
			if (cc.Count == 0 && !string.IsNullOrEmpty(mailControl.MailCreationControl.txtCC.Text))
				cc.Add(mailControl.MailCreationControl.txtCC.Text);

			var to =
				mailControl.MailCreationControl.txtTo.Text.Replace(" ", "").Split(new[] {";"}, StringSplitOptions.RemoveEmptyEntries)
					.ToList();
			if (to.Count == 0 && !string.IsNullOrEmpty(mailControl.MailCreationControl.txtTo.Text))
				to.Add(mailControl.MailCreationControl.txtTo.Text);

			var subject = mailControl.MailCreationControl.txtSubject.Text;
			if (string.IsNullOrEmpty(subject))
				subject = "No subject";

			var bdy = mailControl.MailCreationControl.txtBody.Text;

			EmailHeader header = new EmailHeader
			{
				BCCs = bcc,
				CCs = cc,
				Recipients = to,
				EmailBodyId = Guid.NewGuid().ToLong(),
				Id = Guid.NewGuid().ToLong(),
				Subject = subject
			};
			EmailBody body = new EmailBody
			{
				AttachmentIds = null,
				Id = header.EmailBodyId,
				Message = bdy
			};
			App.Client.SendEmailAsync(App.InternalSessionId, SystemId, _currentAccount.Id, header, body);
		}

		private void ClientSendEmailCompleted(object sender, SendEmailCompletedEventArgs e)
		{
			App.Client.SendEmailCompleted -= ClientSendEmailCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (!e.Result)
				MessageBox.Show("A problem was encountered during sending of this email. Please check your recipient addresses.",
				                "Email sending failed", MessageBoxButton.OK);
			else
			{
				Load(SystemId);
			}
		}

		private void ClientGetHostnameAddressCompleted(object sender, GetHostnameAddressCompletedEventArgs e)
		{
			App.Client.GetHostnameAddressCompleted -= ClientGetHostnameAddressCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			mailControl.HostNameAddress = e.Result;
		}

		#region account creation

		private void MailControlCreateAccount(object sender, MailCreateAccountEventArgs e)
		{
			TheGameServiceClient client = App.Client;
			client.CreateEmailAccountCompleted += ClientCreateEmailAccountCompleted;
			client.CreateEmailAccountAsync(App.InternalSessionId, SystemId, e.Username);
		}

		private void ClientCreateEmailAccountCompleted(object sender, CreateEmailAccountCompletedEventArgs e)
		{
			App.Client.CreateEmailAccountCompleted -= ClientCreateEmailAccountCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result)
				Load(SystemId);
		}

		#endregion

		#region email viewing

		private void MailControlMailSelected(object sender, MailViewEventArgs e)
		{
			TheGameServiceClient client = App.Client;
			_currentlyViewing = (from x in _currentlyViewingEmailHeaders where x.Id == e.MessageId select x).FirstOrDefault();
			client.GetEmailBodyCompleted += ClientGetEmailBodyCompleted;
			client.GetEmailBodyAsync(App.InternalSessionId, SystemId, _currentAccount.Id, e.MessageId);
		}

		private void ClientGetEmailBodyCompleted(object sender, GetEmailBodyCompletedEventArgs e)
		{
			App.Client.GetEmailBodyCompleted -= ClientGetEmailBodyCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result != null)
			{
				mailControl.MailView = new MailViewControl
				{
					Subject = _currentlyViewing.Subject,
					From = _currentlyViewing.From,
					CC = string.Join("; ", _currentlyViewing.CCs.ToArray()),
					Body = e.Result.Message
				};
			}
		}

		#endregion

		#region Folder selection

		private void MailControlMailFolderSelected(object sender, MailFolderSelectedEventArgs e)
		{
			TheGameServiceClient client = App.Client;
			_folder = e.FolderType;
			client.GetEmailsForFolderCompleted += ClientGetEmailsForFolderCompleted;
			EmailFolder emailFolder = EmailFolder.Inbox;
			switch (e.FolderType)
			{
			case MailFolderType.Inbox:
				emailFolder = EmailFolder.Inbox;
				break;
			case MailFolderType.Sent:
				emailFolder = EmailFolder.Sent;
				break;
			case MailFolderType.Spam:
				emailFolder = EmailFolder.Spam;
				break;
			case MailFolderType.Trash:
				emailFolder = EmailFolder.Trash;
				break;
			}
			client.GetEmailsForFolderAsync(App.InternalSessionId, SystemId, _currentAccount.Id, emailFolder);
		}

		private void ClientGetEmailsForFolderCompleted(object sender, GetEmailsForFolderCompletedEventArgs e)
		{
			App.Client.GetEmailsForFolderCompleted -= ClientGetEmailsForFolderCompleted;
			_currentlyViewingEmailHeaders.Clear();
			_currentlyViewingHeaders.Clear();
			mailControl.SelectFolderItem(_folder);
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result != null)
			{
				_currentlyViewingEmailHeaders = e.Result;
				mailControl.MailHeaders = new ObservableCollection<MailControlMailHeader>(
					from x in e.Result.OrderByDescending(it => it.CreationTimestamp)
					select new MailControlMailHeader
					{
						Id = x.Id,
						SenderAddress = x.From,
						SentTime = x.CreationTimestamp,
						Subject = x.Subject
					});
			}
		}

		#endregion

		#region Account selection

		private void MailControlMailAccountSelected(object sender, MailAccountSelectedEventArgs e)
		{
			//go directly to inbox
			_currentAccount = (from x in _availableAccountInfo where x.Id == e.AccountId select x).FirstOrDefault();
			if (_currentAccount == null)
				throw new Exception("Nonexistant account selected. Notify support.");

			MailControlMailFolderSelected(sender, new MailFolderSelectedEventArgs {FolderType = MailFolderType.Inbox});
		}

		private void ClientGetEmailAccountsForSystemCompleted(object sender, GetEmailAccountsForSystemCompletedEventArgs e)
		{
			App.Client.GetEmailAccountsForSystemCompleted -= ClientGetEmailAccountsForSystemCompleted;
			if (e.Error != null)
			{
				App.ServerError();
				return;
			}
			if (e.Result != null) //if there are any accounts here
			{
				if (e.Result.Count == 1 && e.Result[0] != null) //if there is exactly one account here
				{
					_currentAccount = e.Result.First();
					VisualStateManager.GoToState(mailControl, "Normal", false);
					MailControlMailFolderSelected(sender, new MailFolderSelectedEventArgs {FolderType = _folder});
				}
				else
				{
					VisualStateManager.GoToState(mailControl, "Hacked", false);
					_availableAccountInfo.Clear();
					_availableAccountInfo = e.Result.Where(it => it != null).ToList();
					_availableAccounts.Clear();
					e.Result.Where(it => it != null).ToList().ForEach(
						it => _availableAccounts.Add(new MailControlAccountInfo {Id = it.Id, Name = it.Name}));
				}
			}
			else
				//if(e.Result == null || e.Result.Count == 0) // no email account found. If hacked, all email accounts come here, else only the user's, or null.
			{
				VisualStateManager.GoToState(mailControl, "NoAccount", false);
				return;
			}
		}

		#endregion
	}

	public class FeatureMailUiFactory : UiFactoryBase
	{
		public override InterfaceCategory UiCategory
		{
			get { return InterfaceCategory.SystemFeature; }
		}

		public override IProcess CreateProgram()
		{
			return new FeatureMailControl();
		}
	}
}